-
Notifications
You must be signed in to change notification settings - Fork 829
Add community demo: error localization engine (Closes #1761) #1880
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
📝 WalkthroughWalkthroughAdds a complete error localization demo under Changes
Sequence Diagram(s)sequenceDiagram
participant Browser as User/Browser
participant Frontend as Frontend App
participant Server as Express Server
participant Localizer as Localizer Middleware
participant Auth as Auth Route
participant LingoClient as Lingo Client
participant LingoAPI as Lingo.dev API
Browser->>Frontend: select language & submit signup form
Frontend->>Server: POST /api/auth/signup?lang=es (email,password)
Server->>Localizer: incoming request
Localizer->>Server: set req.targetLang = "es"
Server->>Auth: validate input
alt validation fails
Auth->>LingoClient: localizeError(errorMessage,"es")
LingoClient->>LingoAPI: request translation (or mock)
LingoAPI-->>LingoClient: translated message
LingoClient-->>Auth: localized message
Auth-->>Server: 4xx response (localized)
else validation passes
Auth->>LingoClient: localizeError(successMessage,"es")
LingoClient->>LingoAPI: request translation (or mock)
LingoAPI-->>LingoClient: translated message
LingoClient-->>Auth: localized message
Auth-->>Server: 200 response (localized)
end
Server-->>Frontend: JSON response (localized)
Frontend-->>Browser: display localized message
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@community/error-localization-engine/middleware/localizer.js`:
- Around line 7-20: Normalize the derived lang before assigning req.targetLang:
if req.query.lang is an array or object, coerce it to a string by taking the
first element/value; when parsing req.headers['accept-language'], split on ','
then drop any quality suffix by splitting on ';' and trimming the result;
lowercase or otherwise normalize the token (e.g., toLowerCase()) and optionally
validate it against a simple BCP-47-ish pattern before assigning to
req.targetLang; finally fall back to 'en' if the normalized value is empty or
invalid. Ensure you update the logic around req.query.lang, acceptLang (the
variable from req.headers['accept-language']), and the final assignment to
req.targetLang.
In `@community/error-localization-engine/README.md`:
- Around line 40-90: Add a short clarifying note under the "🧪 Testing the API"
section (before the examples for English/Spanish/French) that explains if
LINGO_API_KEY is not set the server runs in mock mode and localized responses
may be mock-prefixed (e.g., "[es] ..." or "[fr] ...") rather than fully
translated; mention that real translations are returned when LINGO_API_KEY is
provided and that language detection still follows the `?lang=xx` query
parameter and `Accept-Language` header priority rules already described.
In `@community/error-localization-engine/routes/auth.js`:
- Around line 73-78: The token is being passed into localizeError (see
localizeError call creating successMsg) which may try to translate it; change
the flow so you first call localizeError with only translatable fields (e.g.,
message) to get the localized payload, then attach the non-translatable token
field (e.g., token: "fake-jwt-token-123456") onto the returned object before
sending res.json, ensuring localizeError is not given the token.
In `@community/error-localization-engine/verify.js`:
- Around line 1-72: The script currently hardcodes port 3000 and always expects
mock-prefixed localization; update runTests to require('dotenv').config(), build
baseURL using const port = process.env.PORT || 3000 and const baseURL =
`http://127.0.0.1:${port}/api/auth`, and detect mock mode via a boolean like
const isMock = !process.env.LINGO_API_KEY || process.env.LINGO_API_KEY ===
'your_lingo_api_key_here'; then adjust the localization assertions (in the POST
/signup error checks and success check) to only expect the mock prefix
'[es]'/'[fr]' when isMock is true, otherwise validate that translated messages
exist without assuming the mock prefix.
🧹 Nitpick comments (4)
community/error-localization-engine/package.json (1)
6-9: Declare a minimum Node version fornode --watch.The
devscript depends onnode --watch, which isn’t available in older Node LTS. Consider adding anengines.nodeconstraint (or a fallback dev script) to prevent confusing runtime errors.♻️ Suggested adjustment
"scripts": { "start": "node server.js", "dev": "node --watch server.js" }, + "engines": { + "node": ">=18.11" + }, "dependencies": {community/error-localization-engine/server.js (1)
29-34: Move dynamic require to module level.The
require('./lingoClient')inside the route handler is evaluated on every request. Move it to the top with other imports for efficiency.Suggested fix
const localizer = require('./middleware/localizer'); const authRoutes = require('./routes/auth'); +const { localizeError } = require('./lingoClient'); const app = express();Then update the route:
// Root endpoint app.get('/', async (req, res) => { - const { localizeError } = require('./lingoClient'); const msg = await localizeError("Welcome to the Error Localization Engine Demo API!", req.targetLang); res.send(msg); });community/error-localization-engine/public/app.js (1)
17-24: Consider encoding the language parameter.While the current language values (en, es, fr, de, hi, ja) are safe, using
encodeURIComponentis a good defensive practice for query parameters.Suggested fix
- const response = await fetch(`/api/auth/signup?lang=${language}`, { + const response = await fetch(`/api/auth/signup?lang=${encodeURIComponent(language)}`, {community/error-localization-engine/lingoClient.js (1)
32-42: Mock mode doesn't handle nested objects.The mock translation only processes top-level string values. Nested objects are copied as-is, which may produce inconsistent behavior between mock and API modes. This is acceptable for the demo's use case (flat error objects), but worth documenting.
For a more robust mock (optional enhancement):
Recursive mock translation
+ const mockTranslateObject = (obj) => { + const translated = {}; + for (const [key, value] of Object.entries(obj)) { + if (typeof value === 'string') { + translated[key] = mockTranslate(value); + } else if (typeof value === 'object' && value !== null) { + translated[key] = mockTranslateObject(value); + } else { + translated[key] = value; + } + } + return translated; + }; + if (isString) { return mockTranslate(content); } else { - const translated = {}; - for (const [key, value] of Object.entries(content)) { - if (typeof value === 'string') { - translated[key] = mockTranslate(value); - } else { - translated[key] = value; - } - } - return translated; + return mockTranslateObject(content); }
|
hey, your PR is missing changeset. Please add the changeset by following instructions here. Make sure you've joined our discord to see this message. If you haven't you need to:
Please also sign your commits Please also go through the comments. |
- Add changeset describing community demo addition - Fix language normalization in middleware (handle arrays and quality values) - Prevent token field from being localized in auth routes - Add mock mode documentation note in README
- Read PORT from .env instead of hardcoding 3000 - Detect mock mode based on LINGO_API_KEY presence - Adjust localization assertions for both mock and live modes
|
Thank you for your contribution! However, this PR references issue #1761, but you're not currently assigned to it. Please get assigned to the issue first, or find an unassigned issue to work on from our issue tracker. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@community/error-localization-engine/verify.js`:
- Around line 9-17: The live-mode branch of checkLocalization currently returns
true for any non-empty msg (isMockMode false), allowing missing translations to
slip through; change checkLocalization (and callers if needed) so that in live
mode it compares msg against the English baseline (e.g., fetch the English text
via an englishMessages map or getEnglishMessage(lang) and ensure msg !==
englishMsg and msg is non-empty), or alternatively update the function signature
to accept an englishBaseline parameter and use that comparison instead of
unconditionally returning true; keep the isMockMode path unchanged.
🧹 Nitpick comments (1)
community/error-localization-engine/verify.js (1)
19-87: Verification can pass on unexpected status codes and never fails the process.
Right now any error response (even 500) can still report PASS, and the script exits with code 0. This makes automated verification unreliable. Consider tracking failures, asserting expected 400s, and setting a non‑zero exit code.🛠️ Suggested tightening of verification behavior
async function runTests() { - + let failed = false; + console.log('--- Starting Verification ---'); @@ - if (err.response) { + if (err.response) { + if (err.response.status !== 400) { + failed = true; + console.log(`❌ FAIL: Expected 400, got ${err.response.status}`); + } console.log('Response Status:', err.response.status); console.log('Response Body:', err.response.data); const msg = err.response.data.message || ''; if (checkLocalization(msg, 'es')) { console.log('✅ PASS: Localized to Spanish'); } else { + failed = true; console.log('❌ FAIL: Not localized correctly'); } } else { + failed = true; console.error('❌ FAIL: Network/Server Error:', err.message); } } @@ - if (err.response) { + if (err.response) { + if (err.response.status !== 400) { + failed = true; + console.log(`❌ FAIL: Expected 400, got ${err.response.status}`); + } console.log('Response Status:', err.response.status); console.log('Response Body:', err.response.data); const msg = err.response.data.message || ''; if (checkLocalization(msg, 'fr')) { console.log('✅ PASS: Localized to French'); } else { + failed = true; console.log('❌ FAIL: Not localized correctly'); } } else { + failed = true; console.error('❌ FAIL: Network/Server Error:', err.message); } } @@ if (res.data.message && !res.data.message.includes('[')) { console.log('✅ PASS: English default (no mock prefix)'); } else { + failed = true; console.log('❌ FAIL: Unexpected content in success message'); } } catch (err) { + failed = true; console.error('❌ FAIL: Unexpected Error:', err.response ? err.response.data : err.message); } + + if (failed) process.exitCode = 1; }
| function checkLocalization(msg, lang) { | ||
| if (!msg) return false; | ||
| if (isMockMode) { | ||
| return msg.includes(`[${lang}]`); | ||
| } | ||
| // In live mode, just check that message exists and is different from English | ||
| console.log(`ℹ️ Live mode detected; skipping mock-prefix assertion for ${lang}.`); | ||
| return true; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Live-mode localization check always passes.
In live mode, checkLocalization returns true for any non-empty message (Line 14-16), so the test won’t catch missing translations. Consider comparing against an English baseline (or adjust the comment/behavior to avoid false positives).
🤖 Prompt for AI Agents
In `@community/error-localization-engine/verify.js` around lines 9 - 17, The
live-mode branch of checkLocalization currently returns true for any non-empty
msg (isMockMode false), allowing missing translations to slip through; change
checkLocalization (and callers if needed) so that in live mode it compares msg
against the English baseline (e.g., fetch the English text via an
englishMessages map or getEnglishMessage(lang) and ensure msg !== englishMsg and
msg is non-empty), or alternatively update the function signature to accept an
englishBaseline parameter and use that comparison instead of unconditionally
returning true; keep the isMockMode path unchanged.
Error Message & Validation Localization Engine
This PR adds a community demo under
/communitythat showcases how Lingo.dev can be used to dynamically localize backend error and validation messages.This submission is part of the community demo initiative.
Closes #1761
🎯 Overview
A production-grade demo showcasing automatic backend error localization. This addresses a common pain point: most applications translate UI labels but leave backend errors in English.
🚀 What This Demo Does
This project demonstrates dynamic backend error localization - intercepting validation errors before they reach the client and translating them to the user's preferred language in real-time.
Key Features:
?lang=xxquery parameters andAccept-Languageheaders🛠️ Tech Stack
lingo.dev/sdk)📂 Project Structure
community/error-localization-engine
├── server.js # Express server with CORS
├── lingoClient.js # Lingo.dev SDK wrapper
├── middleware/localizer.js # Language detection middleware
├── routes/auth.js # Auth endpoints with validation
└── public/ # Frontend UI
├── index.html
├── styles.css
└── app.js
🧪 How to Test
npm install.envnpm starthttp://localhost:3000💡 Why This Matters
Most developers focus on UI localization but forget about backend errors. This demo shows a scalable pattern for:
Demo Screenshots :
Summary by CodeRabbit
New Features
Documentation
Chores
✏️ Tip: You can customize this high-level summary in your review settings.